package com.laituo.juyou.launcher.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.laituo.juyou.app.config.alipay.AliProperties;
import com.laituo.juyou.biz.service.notify.AdminNotifyBizService;
import com.laituo.juyou.biz.service.order.OrderBizService;
import com.laituo.juyou.biz.service.user.UserBizService;
import com.laituo.juyou.core.Const;
import com.laituo.juyou.core.exception.ServiceException;
import com.laituo.juyou.data.component.CacheComponent;
import com.laituo.juyou.data.domain.*;
import com.laituo.juyou.data.dto.order.OrderDTO;
import com.laituo.juyou.data.dto.order.OrderRiderDTO;
import com.laituo.juyou.data.enums.OrderStatusType;
import com.laituo.juyou.data.mapper.*;
import com.laituo.juyou.plugin.core.inter.IPluginPaySuccess;
import com.laituo.juyou.plugin.core.manager.PluginsManager;
import io.goeasy.GoEasy;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.security.Security;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by rize on 2019/7/10.
 */
@RestController
@RequestMapping("/cb")
public class CallbackController {

    private static final Logger logger = LoggerFactory.getLogger(CallbackController.class);

    @Autowired
    private OrderBizService orderBizService;

    @Autowired
    private UserBizService userBizService;

    @Autowired
    private SpuMapper spuMapper;

    @Autowired
    private OrderSkuMapper orderSkuMapper;

    @Autowired
    private GroupShopMapper groupShopMapper;

    @Autowired
    private WxPayService wxPayService;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private PluginsManager pluginsManager;

    @Autowired
    private GroupShopUserMapper groupShopUserMapper;

    @Autowired
    private CacheComponent cacheComponent;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AliProperties aliProperties;

    @Autowired
    private AdminNotifyBizService adminNotifyBizService;

    @RequestMapping("/wxpay")
    @Transactional(rollbackFor = Exception.class)
    public Object wxpay(@RequestBody String body) throws Exception {
        WxPayOrderNotifyResult result = null;
        try {
            result = wxPayService.parseOrderNotifyResult(body);
        } catch (WxPayException e) {
            logger.error("[微信解析回调请求] 异常", e);
            return WxPayNotifyResponse.fail(e.getMessage());
        }
        logger.info("处理腾讯支付平台的订单支付");
        logger.info(JSONObject.toJSONString(result));

        /* 之前传过去的我们系统的订单ID */
        String orderNo = result.getOutTradeNo();
        String payId = result.getTransactionId();
        Integer totalFee = result.getTotalFee();
        this.payNotify(orderNo, "WX", totalFee, payId);
        //通知管理员发货
//        OrderDTO finalOrderDTO = orderDTO;
//        GlobalExecutor.execute(() -> {
//            adminNotifyBizService.newOrder(finalOrderDTO);
//        });


        return WxPayNotifyResponse.success("支付成功");
    }


    @Transactional(rollbackFor = Exception.class)
    @RequestMapping("aliPay")
    public void couponAliPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>(20);
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //验签
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        boolean flag = AlipaySignature.rsaCertCheckV1(params, aliProperties.getAlipayCertPath(), aliProperties.getCharset(), aliProperties.getSignType());
        AlipayNotifyParam param = BeanUtil.mapToBean(params, AlipayNotifyParam.class, true);
        String trade_status = param.getTradeStatus();
        if (trade_status.equals("TRADE_SUCCESS")
                || trade_status.equals("TRADE_FINISHED")) {
            if (flag && params.get("subject").equals(param.getOutTradeNo())) {
                String orderNo = param.getOutTradeNo();
                String payId = param.getTradeNo();
                Integer totalFee = param.getTotalAmount().multiply(new BigDecimal(100)).intValue();
                this.payNotify(orderNo, "ALIPAY", totalFee, payId);
            } else {
                response.getWriter().print("failure");
            }
        }
    }

    /**
     * @param orderNo
     * @param payType
     * @param totalFee
     * @return
     */
    Object payNotify(String orderNo, String payType, Integer totalFee, String payId) throws ServiceException {
        List<OrderDO> orderDOList = orderMapper.selectList(
                new EntityWrapper<OrderDO>()
                        .eq("order_no", orderNo));

        if (CollectionUtils.isEmpty(orderDOList)) {
            logger.warn("订单不存在 orderNo=" + orderNo);
            return WxPayNotifyResponse.fail("订单不存在 orderNo=" + orderNo);
        }

        OrderDO order = orderDOList.get(0);

        // 检查这个订单是否已经处理过
        if (order.getStatus() != OrderStatusType.UNPAY.getCode()) {
            logger.warn("订单已经处理成功!" + orderNo);
            return WxPayNotifyResponse.success("订单已经处理成功!");
        }

        // 检查支付订单金额
        if (!totalFee.equals(order.getActualPrice())) {
            logger.warn(order.getOrderNo() + " : 支付金额不符合 totalFee=" + totalFee);
            return WxPayNotifyResponse.fail(order.getOrderNo() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        //**************** 在此之前都没有 数据库修改 操作 所以前面是直接返回错误的 **********************//
        OrderDO updateOrderDO = new OrderDO();
        updateOrderDO.setPayId(payId);
        updateOrderDO.setPayChannel(payType);
        updateOrderDO.setPayPrice(totalFee);
        updateOrderDO.setGmtPay(new Date());
        updateOrderDO.setGmtUpdate(order.getGmtPay());
        String groupNo = "";
        //团购处理
        if (null != order.getGroupShopId()) {
            Wrapper<GroupShopUserDO> wrapper = new EntityWrapper<GroupShopUserDO>()
                    .eq("order_id", orderNo).eq("status", 0);
            //拼团回调
            List<GroupShopUserDO> groupInfo = groupShopUserMapper.selectList(wrapper);
            //拼团信息
            GroupShopDO groupShopDO = cacheComponent.getHashObj(Const.GROUP_SHOP_INFO, order.getGroupShopId().toString(), GroupShopDO.class);
            if (null == groupShopDO) {
                groupShopDO = groupShopMapper.selectById(order.getGroupShopId());
            }
            if (groupInfo.size() > 0) {
                GroupShopUserDO groupShopUserDO = groupInfo.get(0);
                String raw = cacheComponent.getRaw(Const.GROUP_USER_NUM + groupShopUserDO.getGroupNo());
                int count = Integer.parseInt(StrUtil.isBlank(raw) ? "0" : raw);
                groupNo = groupShopUserDO.getGroupNo();
                if (count == 0) {
                    GroupShopUserDTO groupShopUserDTO = new GroupShopUserDTO();
                    groupShopUserDTO.setCreater(groupShopUserDO.getCreateId());
                    groupShopUserDTO.setGroupShopNo(groupShopUserDO.getGroupNo());
                    groupShopUserDTO.setGmtCreate(groupShopUserDO.getGmtCreate());
                    groupShopUserDTO.setMinNum(groupShopDO.getMinimumNumber());
                    UserDO userDO = userMapper.selectById(groupShopUserDO.getUserId());
                    groupShopUserDTO.setImg(userDO == null ? "-1" : StrUtil.isBlank(userDO.getAvatarUrl()) ? "-1" : userDO.getAvatarUrl());
                    groupShopUserDTO.setUserName(userDO == null ? "-1" : StrUtil.isBlank(userDO.getNickname()) ? "-1" : userDO.getNickname());
                    //半小时失效时间
                    cacheComponent.putObj(Const.GROUP_USER_INFO + groupShopUserDO.getGroupNo(), groupShopUserDTO, Const.CACHE_HALF_HOUR);
                    cacheComponent.putRaw(Const.GROUP_USER_NUM + groupShopUserDO.getGroupNo(), "1", Const.CACHE_HALF_HOUR);
                } else {
                    cacheComponent.incRaw(Const.GROUP_USER_NUM + groupShopUserDO.getGroupNo());
                }
            }
            updateOrderDO.setStatus(OrderStatusType.GROUP_SHOP_WAIT.getCode());
            //修改订单状态 等待拼团
            orderBizService.changeOrderStatus(orderNo, OrderStatusType.UNPAY.getCode(), updateOrderDO);
            //拼单修改状态
            if (order.getGroupShopId() != null && StrUtil.isNotBlank(groupNo)) {

                String raw = cacheComponent.getRaw(Const.GROUP_USER_NUM + groupNo);
                int count = Integer.parseInt(StrUtil.isBlank(raw) ? "0" : raw);
                //拼团成功
                if (count >= groupShopDO.getMinimumNumber()) {
                    Wrapper<GroupShopUserDO> wrapper1 = new EntityWrapper<GroupShopUserDO>().eq("group_no", groupNo).eq("status", 1);
                    List<GroupShopUserDO> info = groupShopUserMapper.selectList(wrapper1);
                    List<String> collect = info.stream().map(item -> {
                        return item.getOrderId();
                    }).collect(Collectors.toList());
                    //订单信息
                    OrderDO updateOrderDO1 = new OrderDO();
                    updateOrderDO1.setStatus(OrderStatusType.WAIT_STOCK.getCode());
                    //拼团人员信息
                    GroupShopUserDO groupShopUserDO = new GroupShopUserDO();
                    //完成拼单
                    groupShopUserDO.setStatus("2");
                    for (String s : collect) {
                        //修改订单状态
                        changeOrderStatus(s, updateOrderDO1, groupShopUserDO);
                    }
                    //修改订单状态
                    changeOrderStatus(orderNo, updateOrderDO1, groupShopUserDO);
                    //删除redis信息
                    cacheComponent.del(Const.GROUP_USER_INFO + groupNo);
                    cacheComponent.del(Const.GROUP_USER_NUM + groupNo);
                    //增加订单信息到redis中
                    collect.add(orderNo);
                    List<OrderDO> orderList = orderMapper.selectList(new EntityWrapper<OrderDO>().in("order_no", collect));
                    for (OrderDO orderDO : orderList) {
                        addRiderOrder(orderDO);
                    }
                } else {
                    GroupShopUserDO groupShopUserDO = new GroupShopUserDO();
                    groupShopUserDO.setStatus("1");
                    groupShopUserMapper.update(groupShopUserDO, wrapper);
                }
            } else {
                logger.warn("支付回调未查询到团购信息!" + orderNo);
            }

        } else {
            updateOrderDO.setStatus(OrderStatusType.WAIT_STOCK.getCode());
            orderBizService.changeOrderStatus(orderNo, OrderStatusType.UNPAY.getCode(), updateOrderDO);
            //提交订单信息到redis,供骑手抢购
            addRiderOrder(order);
            List<OrderSkuDO> orderSkuDOList = orderSkuMapper.selectList(
                    new EntityWrapper<OrderSkuDO>()
                            .eq("order_no", orderNo));
            orderSkuDOList.forEach(item -> {
                //增加销量
                spuMapper.incSales(item.getSpuId(), item.getNum());
                if (order.getGroupShopId() != null) {
                    //增加团购人数, 若想算商品数这里就获取orderSku的数量，若想算人数，这里就写1
                    groupShopMapper.incCurrentNum(order.getGroupShopId(), item.getNum());
                }
            });
            OrderDTO orderDTO = new OrderDTO();
            BeanUtils.copyProperties(order, orderDTO);
            orderDTO.setPayChannel(updateOrderDO.getPayChannel());
            orderDTO.setSkuList(orderSkuDOList);
            List<IPluginPaySuccess> plugins = pluginsManager.getPlugins(IPluginPaySuccess.class);
            if (!CollectionUtils.isEmpty(plugins)) {
                String formId = userBizService.getValidFormIdByUserId(orderDTO.getUserId()).getFormId();
                for (IPluginPaySuccess paySuccess : plugins) {
                    orderDTO = paySuccess.invoke(orderDTO, formId);
                }
            }
        }
        return WxPayNotifyResponse.success("支付成功");
    }

    /**
     * 添加订单数据到redis中
     *
     * @param order
     */
    public void addRiderOrder(OrderDO order) {
        //增加订单信息到redis中
        OrderRiderDTO orderRiderDTO = new OrderRiderDTO();
        StringBuffer toAddress = new StringBuffer(order.getProvince());
        toAddress.append(order.getCity())
                .append(order.getCounty())
                .append(order.getAddress())
                .append(order.getConsignee());
        orderRiderDTO.setGetAddress(order.getStorageName());
        orderRiderDTO.setOrderNo(order.getOrderNo());
        orderRiderDTO.setToAddress(toAddress.toString());
        cacheComponent.putHashRaw(Const.RIDER_ORDER + order.getStoreId(), order.getOrderNo(), JSONUtil.toJsonStr(orderRiderDTO));
        //消息推送
        orderPush();
    }

    /**
     * 修改订单状态，团组人员状态
     *
     * @param orderNo         订单号
     * @param updateOrderDO1
     * @param groupShopUserDO
     * @throws ServiceException
     */
    public void changeOrderStatus(String orderNo, OrderDO updateOrderDO1, GroupShopUserDO groupShopUserDO) throws ServiceException {
        //修改订单状态
        orderBizService.changeOrderStatus(orderNo, OrderStatusType.GROUP_SHOP_WAIT.getCode(), updateOrderDO1);
        //修改拼单人状态
        Wrapper<GroupShopUserDO> wrapper2 = new EntityWrapper<GroupShopUserDO>().eq("order_id", orderNo);
        groupShopUserMapper.update(groupShopUserDO, wrapper2);
    }

    /**
     * 消息推送
     */
    public void orderPush() {
        GoEasy goEasy = new GoEasy("http://rest-hangzhou.goeasy.io", "BC-7b7804e8d25e4f3c98115b033e421d2f");
        goEasy.publish("rider_channel", "新订单提醒", "新的订单", "新订单");
    }
}
